﻿// Copyright (c)  MOKEYISH. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Text;
using NSQL.Expressions;
using NSQL.Expressions.Functions;
using NSQL.Extensions;
using NSQL.Generator.Formatters;
using NSQL.LogicalResource;
using NSQL.Statements;

namespace NSQL.Generator
{
    public class NpgsqlGenerator : BaseGenerator, ISqlGenerator, IFunctionVisitor<StringBuilder>
    {
        protected override string ToChar => Format("to_char");

        protected string Offset => Format(nameof(Offset));
        protected string Coalesce => Format(nameof(Coalesce));
        protected string Except => Format(nameof(Except));
        protected override string PadLeft => Format("LPad");
        protected override string PadRight => Format("RPad");
        protected override string TrimStart => Format("LTrim");
        protected override string TrimEnd => Format("RTrim");

        protected override StringBuilder FormatSelect(StringBuilder select, StringBuilder from, StringBuilder where, StringBuilder group,
            StringBuilder order, StringBuilder having, int skip, int limit)
        {
            var builder = FormatSelect(select, from, where, group, order, having);
            if (skip > 0)
            {
                builder.Append(' ').Append(Offset);
                builder.Append(' ').Append(skip);
            }

            if (limit <= 0) return builder;
            builder.Append(' ').Append(Limit);
            builder.Append(' ').Append(limit);
            return builder;
        }
        
        string ISqlGenerator.Generate(MinusStatement statement)
        {
            var builder = new StringBuilder();
            builder.Append(statement.Left.Accept(this));
            builder.Append(' ').Append(Except).Append(' ');
            builder.Append(statement.Right.Accept(this));
            return builder.ToString();
        }
        
        StringBuilder IFunctionVisitor<StringBuilder>.Visit(INvlFunction nvlFunction)
        {
            var hasThen = !(nvlFunction.Then is null);

            if (hasThen)
            {
                return new MatchExpression(
                    new[]
                    {
                        new MatchPair<ILogicalExpression, IValueExpression>()
                        {
                            When = nvlFunction.Expr.IsNull(),
                            Then = nvlFunction.Default
                        }
                    },
                    nvlFunction.Then).Accept(this);
            }
            else
            {
                var builder = new StringBuilder();
                builder.Append(Coalesce);
                builder.Append('(');
                builder.Append(nvlFunction.Expr.Accept(this));
                builder.Append(", ").Append(nvlFunction.Default.Accept(this));
                builder.Append(')');
                return builder;
            }
        }

        public NpgsqlGenerator(SqlGeneratorSettings settings) : base(settings)
        {
        }
    }
    
    public static class NpgsqlFormatterExtensions
    {
        public static string ToNpgsql(this IStatement statement, SqlGeneratorSettings settings = null)
        {
            return new NpgsqlGenerator(settings ?? new SqlGeneratorSettings
            {
                KeywordStyle = KeywordStyle.LowerCase
            }).Generate(statement);
        }
        public static string ToNpgsql(this IStatement statement, ILogicalDatabase database)
        {
            return new NpgsqlGenerator(new SqlGeneratorSettings
            {
                Database = database,
                KeywordStyle = KeywordStyle.LowerCase
            }).Generate(statement);
        }
    }
}